package com.example.boardroom.serial.table.ModbusRtu;

import static com.example.boardroom.serial.table.ModbusRtu.ParseSystemUtil.decToHex;

import android.content.Context;
import android.os.SystemClock;
import android.util.Log;

import com.blankj.utilcode.util.LogUtils;

import org.jetbrains.annotations.NotNull;

import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;

import android_serialport_api.SerialPortFinder;
import tp.xmaihh.serialport.SerialHelper;
import tp.xmaihh.serialport.bean.ComBean;
import tp.xmaihh.serialport.stick.AbsStickPackageHelper;
import tp.xmaihh.serialport.utils.ByteUtil;

public class ModbusUtils {
    public static String TAG = "lufei";
    public static String ERROR = "解析错误";
    public static DecimalFormat df = new DecimalFormat("######0.00");
    private static SerialHelper serialHelper = null;
    private static final String sPort = "/dev/ttyS3";
    private static final int iBaudRate = 9600;





    public static SerialHelper initSerialHelper() {
        if (null == serialHelper) {
            serialHelper = new SerialHelper(sPort, iBaudRate) {
                @Override
                protected void onDataReceived(ComBean paramComBean) {
                    //广播应答帧

//                    EventBus.getDefault().post(new ModBusEvent(paramComBean));
                }
            };

            LogUtils.dTag(TAG, "新的");
            return serialHelper;
        }
        LogUtils.dTag(TAG, "旧的");
        /*
         * 默认的BaseStickPackageHelper将接收的数据扩展成64位，一般用不到这么多位
         * 我这里重新设定一个自适应数据位数的
         */
        serialHelper.setStickPackageHelper(new AbsStickPackageHelper() {
            @Override
            public byte[] execute(InputStream is) {
                try {
                    int available = is.available();
                    if (available > 0) {
                        byte[] buffer = new byte[available];
                        int size = is.read(buffer);
                        if (size > 0) {
                            return buffer;
                        }
                    } else {
                        SystemClock.sleep(50);
                    }

                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
        return serialHelper;
    }


//问询帧是01 03 00 01 00 01 D5 CA

    /**
     * 拼接器  读取温湿度传感器 仅限03
     *直接传入16位的数据
     * @param addressCode          硬件地址
     * @param functionCode         默认读取=03
     * @param registerStartAddress 查询文档寄存器列表起始地址
     * @param registerLength       想查询的寄存器数量
     * @param checkCodeSequence    false 默认低字节在前; true 高字节在前
     * @return 拼装好的发送帧
     */
    public static String splicing(String addressCode, String functionCode, String registerStartAddress, String registerLength, boolean checkCodeSequence) {
        StringBuilder stringBuilder = new StringBuilder();
        //基础数据补位
        addressCode = addressCode.length() <= 1 ? "0" + addressCode : addressCode;
        functionCode = functionCode.length() <= 1 ? "0" + functionCode : functionCode;
        StringBuilder registerStartAddressBuilder = new StringBuilder(registerStartAddress);
        while (registerStartAddressBuilder.length() < 4) {
            registerStartAddressBuilder.insert(0, "0");
        }
        registerStartAddress = registerStartAddressBuilder.toString();
        StringBuilder registerLengthBuilder = new StringBuilder(registerLength);
        while (registerLengthBuilder.length() < 4) {
            registerLengthBuilder.insert(0, "0");
        }
        registerLength = registerLengthBuilder.toString();
        //拼接基础数据
        stringBuilder.append(addressCode);
        stringBuilder.append(functionCode);
        stringBuilder.append(registerStartAddress);
        stringBuilder.append(registerLength);
//        LogUtils.d(TAG, stringBuilder);
        //计算校验码
        byte[] bOutArray = ByteUtil.HexToByteArr(String.valueOf(stringBuilder));
        int compute = CRC16.compute(bOutArray);
        String s = decToHex(compute);
//        LogUtils.d(TAG, s);
        stringBuilder.append(s);
//        LogUtils.d(TAG, "发送帧:" + stringBuilder + "\n转成字节:" + Arrays.toString(ByteUtil.HexToByteArr(String.valueOf(stringBuilder))));
        return String.valueOf(stringBuilder);
    }
//    String str = "0103 04 010F 0126 4B86";//返回帧
//    String ss = "010300000002c40b";//发送帧


    /**
     * 获取可用端口号
     *
     * @return 端口号
     */
    @NotNull
    public static StringBuilder getPath() {
        SerialPortFinder serialPortFinder = new SerialPortFinder();
        String[] allDevicesPath = serialPortFinder.getAllDevicesPath();
        String[] allDevices = serialPortFinder.getAllDevices();
        StringBuilder builder = new StringBuilder();
        builder.append("绝对路径:\n");
        for (String s : allDevicesPath) {
            builder.append(s);
            builder.append("\n");
        }
        builder.append("路径名称:\n");
        for (String allDevice : allDevices) {
            builder.append(allDevice);
            builder.append("\n");
        }
        return builder;
    }

    /**
     * 获取绝对路径
     *
     * @return 绝对路径
     */
    @NotNull
    public static StringBuilder getPaths() {
        SerialPortFinder serialPortFinder = new SerialPortFinder();
        String[] allDevicesPath = serialPortFinder.getAllDevicesPath();
        StringBuilder builder = new StringBuilder();
        builder.append("绝对路径:\n");
        for (String s : allDevicesPath) {
            builder.append(s);
            builder.append("\n");
        }
        return builder;
    }


    //电压,电流,瞬时有功功率,瞬时无功功率,瞬时视在功率,功率因数,电网频率,有功总电能
    //V,A,W,W,W,无,HZ,kWh
//        builder.append("0320000008");//查询8个寄存器地址 电压,电流,瞬时有功功率,瞬时无功功率,瞬时视在功率,功率因数,电网频率,有功总电能


    /**
     * 检查校验码
     *
     * @param data 应答帧
     * @return 返回true则校验通过
     */
    public static boolean check(String data) {
//        String frame = data.replaceAll(" ", "");
//        String value = frame.substring(0, frame.length() - 4);
//        String crc = frame.substring(frame.length() - 4);
//        int compute = CRC16.compute(ByteUtil.HexToByteArr(value));
//        LogUtils.dTag(TAG, "检查校验码\n"+"数据单元:"+value+"\n取出校验码:"+crc+"\n计算出新校验码:"+compute);
//        return compute == covert(crc);
        return true;
    }
    //问询A组:01 01 00 00 00 10 3D C6
    //A组应答:01 01 02 88 0C DF F9
    //问询B组:01 01 00 10 00 10 3C 03
    //B组应答:01 01 02 40 00 88 3C

    /**
     * 闻讯32路A组 所有继电器
     */
    public static String Inquiry32_GroupA() {
        return "01 01 00 00 00 10 3D C6";
    }

    /**
     * 闻讯32路B组 所有继电器
     */
    public static String Inquiry32_GroupB() {
        return "01 01 00 10 00 10 3C 03";
    }

    /**
     * 翻译32路继电器组单组
     *
     * @param data 应答帧
     */
    public static String translateAlone(String data) {
        String frame = data.replaceAll(" ", "");
        if (!check(frame)) {
            return ERROR;
        }
        String value = frame.substring(6, 10);
        if (value.equals("0000")) {
            return "0000000000000000";
        }
        if (ParseSystemUtil.hexStringToByte(value).length() == 16) {
            return ParseSystemUtil.hexStringToByte(value);
        } else {
            //补位
            StringBuilder builder = new StringBuilder();
            builder.append(ParseSystemUtil.hexStringToByte(value));
            while (builder.length() < 16) {
                builder.insert(0, "0");
            }
            return String.valueOf(builder);
        }

    }

    /*
        0x01: 读线圈寄存器
        0x02: 读离散输入寄存器
        0x03: 读保持寄存器
        0x04: 读输入寄存器
        0x05: 写单个线圈寄存器
        0x06: 写单个保持寄存器
        0x0f: 写多个线圈寄存器
        0x10: 写多个保持寄存器
        如上所示一共8种功能码。这其中有涉及到线圈、离散输入、保持、输入四种寄存器。
        原文链接：https://blog.csdn.net/lingshi75/article/details/105991450/
     */


}

